home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / gnulib / dkbtrace / pbmplus / source / pnm / pnmscale.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-10  |  11.5 KB  |  435 lines

  1. /* pnmscale.c - read a portable anymap and scale it
  2. **
  3. ** Copyright (C) 1989, 1991 by Jef Poskanzer.
  4. **
  5. ** Permission to use, copy, modify, and distribute this software and its
  6. ** documentation for any purpose and without fee is hereby granted, provided
  7. ** that the above copyright notice appear in all copies and that both that
  8. ** copyright notice and this permission notice appear in supporting
  9. ** documentation.  This software is provided "as is" without express or
  10. ** implied warranty.
  11. */
  12.  
  13. #include "pnm.h"
  14.  
  15. #define SCALE 4096
  16. #define HALFSCALE 2048
  17.  
  18. void
  19. main( argc, argv )
  20.     int argc;
  21.     char* argv[];
  22.     {
  23.     FILE* ifp;
  24.     xel* xelrow;
  25.     xel* tempxelrow;
  26.     xel* newxelrow;
  27.     register xel* xP;
  28.     register xel* nxP;
  29.     int argn, specxscale, specyscale, specxsize, specysize, specxysize;
  30.     int rows, cols, format, newformat, rowsread, newrows, newcols;
  31.     register int row, col, needtoreadrow;
  32.     xelval maxval;
  33.     float xscale, yscale;
  34.     long sxscale, syscale;
  35.     register long fracrowtofill, fracrowleft;
  36.     long* rs;
  37.     long* gs;
  38.     long* bs;
  39.     char* usage = "<s> [pnmfile]\n            -xsize|width|-ysize|-height <s> [pnmfile]\n            -xscale|-yscale <s> [pnmfile]\n            -xscale|-xsize|-width <s> -yscale|-ysize|-height <s> [pnmfile]\n            -xysize <x> <y> [pnmfile]";
  40.  
  41.     pnm_init( &argc, argv );
  42.  
  43.     argn = 1;
  44.     specxscale = specyscale = specxsize = specysize = specxysize = 0;
  45.  
  46.     while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
  47.     {
  48.     if ( pm_keymatch( argv[argn], "-xscale", 4 ) )
  49.         {
  50.         if ( specxscale )
  51.         pm_error( "already specified an x scale" );
  52.         if ( specxsize )
  53.         pm_error(
  54.             "only one of -xsize/-width and -xscale may be specified" );
  55.         ++argn;
  56.         if ( argn == argc || sscanf( argv[argn], "%f", &xscale ) != 1 )
  57.         pm_usage( usage );
  58.         if ( xscale <= 0.0 )
  59.         pm_error( "x scale must be greater than 0" );
  60.         specxscale = 1;
  61.         }
  62.     else if ( pm_keymatch( argv[argn], "-yscale", 4 ) )
  63.         {
  64.         if ( specyscale )
  65.         pm_error( "already specified a y scale" );
  66.         if ( specysize )
  67.         pm_error(
  68.             "only one of -ysize/-height and -yscale may be specified" );
  69.         ++argn;
  70.         if ( argn == argc || sscanf( argv[argn], "%f", &yscale ) != 1 )
  71.         pm_usage( usage );
  72.         if ( yscale <= 0.0 )
  73.         pm_error( "y scale must be greater than 0" );
  74.         specyscale = 1;
  75.         }
  76.     else if ( pm_keymatch( argv[argn], "-xsize", 4 ) ||
  77.               pm_keymatch( argv[argn], "-width", 2 ) )
  78.         {
  79.         if ( specxsize )
  80.         pm_error( "already specified a width" );
  81.         if ( specxscale )
  82.         pm_error(
  83.             "only one of -xscale and -xsize/-width may be specified" );
  84.         ++argn;
  85.         if ( argn == argc || sscanf( argv[argn], "%d", &newcols ) != 1 )
  86.         pm_usage( usage );
  87.         if ( newcols <= 0 )
  88.         pm_error( "new width must be greater than 0" );
  89.         specxsize = 1;
  90.         }
  91.     else if ( pm_keymatch( argv[argn], "-ysize", 4 ) ||
  92.               pm_keymatch( argv[argn], "-height", 2 ) )
  93.         {
  94.         if ( specysize )
  95.         pm_error( "already specified a height" );
  96.         if ( specyscale )
  97.         pm_error(
  98.             "only one of -yscale and -ysize/-height may be specified" );
  99.         ++argn;
  100.         if ( argn == argc || sscanf( argv[argn], "%d", &newrows ) != 1 )
  101.         pm_usage( usage );
  102.         if ( newrows <= 0 )
  103.         pm_error( "new height must be greater than 0" );
  104.         specysize = 1;
  105.         }
  106.     else if ( pm_keymatch( argv[argn], "-xysize", 3 ) )
  107.         {
  108.         if ( specxsize || specysize || specxscale || specyscale )
  109.         pm_error( "can't use -xysize with any other specifiers" );
  110.         ++argn;
  111.         if ( argn == argc || sscanf( argv[argn], "%d", &newcols ) != 1 )
  112.         pm_usage( usage );
  113.         ++argn;
  114.         if ( argn == argc || sscanf( argv[argn], "%d", &newrows ) != 1 )
  115.         pm_usage( usage );
  116.         if ( newcols <= 0 || newrows <= 0 )
  117.         pm_error( "new width and height must be greater than 0" );
  118.         specxsize = 1;
  119.         specysize = 1;
  120.         specxysize = 1;
  121.         }
  122.     else
  123.         pm_usage( usage );
  124.     ++argn;
  125.     }
  126.  
  127.     if ( ! ( specxscale || specyscale || specxsize || specysize ) )
  128.     {
  129.     /* No flags specified, so a single scale factor is required. */
  130.     if ( argn == argc )
  131.         pm_usage( usage );
  132.     if ( sscanf( argv[argn], "%f", &xscale ) != 1 )
  133.         pm_usage( usage );
  134.     if ( xscale <= 0.0 )
  135.         pm_error( "scale must be greater than 0" );
  136.     ++argn;
  137.     yscale = xscale;
  138.     specxscale = specyscale = 1;
  139.     }
  140.  
  141.     /* Now get input file. */
  142.     if ( argn != argc )
  143.     {
  144.     ifp = pm_openr( argv[argn] );
  145.     ++argn;
  146.     }
  147.     else
  148.     ifp = stdin;
  149.  
  150.     if ( argn != argc )
  151.     pm_usage( usage );
  152.  
  153.     pnm_pbmmaxval = PNM_MAXMAXVAL;  /* use larger value for better results */
  154.     pnm_readpnminit( ifp, &cols, &rows, &maxval, &format );
  155.  
  156.     /* Promote PBM files to PGM. */
  157.     if ( PNM_FORMAT_TYPE(format) == PBM_TYPE )
  158.     {
  159.         newformat = PGM_TYPE;
  160.     pm_message( "promoting from PBM to PGM" );
  161.     }
  162.     else
  163.         newformat = format;
  164.  
  165.     /* Compute all sizes and scales. */
  166.     if ( specxysize )
  167.     if ( (float) newcols / (float) newrows > (float) cols / (float) rows )
  168.         specxsize = 0;
  169.     else
  170.         specysize = 0;
  171.  
  172.     if ( specxsize )
  173.     xscale = (float) newcols / (float) cols;
  174.     else if ( specxscale )
  175.     newcols = cols * xscale + 0.999;
  176.  
  177.     if ( specysize )
  178.     yscale = (float) newrows / (float) rows;
  179.     else if ( specyscale )
  180.     newrows = rows * yscale + 0.999;
  181.     else
  182.     if ( specxsize )
  183.         {
  184.         yscale = xscale;
  185.         newrows = rows * yscale + 0.999;
  186.         }
  187.     else
  188.         {
  189.         yscale = 1.0;
  190.         newrows = rows;
  191.         }
  192.     
  193.     if ( ! ( specxsize || specxscale ) )
  194.     if ( specysize )
  195.         {
  196.         xscale = yscale;
  197.         newcols = cols * xscale + 0.999;
  198.         }
  199.     else
  200.         {
  201.         xscale = 1.0;
  202.         newcols = cols;
  203.         }
  204.  
  205.     sxscale = xscale * SCALE;
  206.     syscale = yscale * SCALE;
  207.  
  208.     xelrow = pnm_allocrow( cols );
  209.     if ( newrows == rows )    /* shortcut Y scaling if possible */
  210.     tempxelrow = xelrow;
  211.     else
  212.     tempxelrow = pnm_allocrow( cols );
  213.     rs = (long*) pm_allocrow( cols, sizeof(long) );
  214.     gs = (long*) pm_allocrow( cols, sizeof(long) );
  215.     bs = (long*) pm_allocrow( cols, sizeof(long) );
  216.     rowsread = 0;
  217.     fracrowleft = syscale;
  218.     needtoreadrow = 1;
  219.     for ( col = 0; col < cols; ++col )
  220.     rs[col] = gs[col] = bs[col] = HALFSCALE;
  221.     fracrowtofill = SCALE;
  222.  
  223.     pnm_writepnminit( stdout, newcols, newrows, maxval, newformat, 0 );
  224.     newxelrow = pnm_allocrow( newcols );
  225.  
  226.     for ( row = 0; row < newrows; ++row )
  227.     {
  228.     /* First scale Y from xelrow into tempxelrow. */
  229.     if ( newrows == rows )    /* shortcut Y scaling if possible */
  230.         {
  231.         pnm_readpnmrow( ifp, xelrow, cols, maxval, format );
  232.         }
  233.     else
  234.         {
  235.         while ( fracrowleft < fracrowtofill )
  236.         {
  237.         if ( needtoreadrow )
  238.             if ( rowsread < rows )
  239.             {
  240.             pnm_readpnmrow( ifp, xelrow, cols, maxval, format );
  241.             ++rowsread;
  242.             /* needtoreadrow = 0; */
  243.             }
  244.                 switch ( PNM_FORMAT_TYPE(format) )
  245.                     {
  246.                     case PPM_TYPE:
  247.             for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
  248.             {
  249.             rs[col] += fracrowleft * PPM_GETR( *xP );
  250.             gs[col] += fracrowleft * PPM_GETG( *xP );
  251.             bs[col] += fracrowleft * PPM_GETB( *xP );
  252.             }
  253.                     break;
  254.  
  255.                     default:
  256.             for ( col = 0, xP = xelrow; col < cols; ++col, ++xP )
  257.             gs[col] += fracrowleft * PNM_GET1( *xP );
  258.                     break;
  259.                     }
  260.         fracrowtofill -= fracrowleft;
  261.         fracrowleft = syscale;
  262.         needtoreadrow = 1;
  263.         }
  264.         /* Now fracrowleft is >= fracrowtofill, so we can produce a row. */
  265.         if ( needtoreadrow )
  266.         if ( rowsread < rows )
  267.             {
  268.             pnm_readpnmrow( ifp, xelrow, cols, maxval, format );
  269.             ++rowsread;
  270.             needtoreadrow = 0;
  271.             }
  272.         switch ( PNM_FORMAT_TYPE(format) )
  273.         {
  274.         case PPM_TYPE:
  275.         for ( col = 0, xP = xelrow, nxP = tempxelrow;
  276.               col < cols; ++col, ++xP, ++nxP )
  277.             {
  278.             register long r, g, b;
  279.  
  280.             r = rs[col] + fracrowtofill * PPM_GETR( *xP );
  281.             g = gs[col] + fracrowtofill * PPM_GETG( *xP );
  282.             b = bs[col] + fracrowtofill * PPM_GETB( *xP );
  283.             r /= SCALE;
  284.             if ( r > maxval ) r = maxval;
  285.             g /= SCALE;
  286.             if ( g > maxval ) g = maxval;
  287.             b /= SCALE;
  288.             if ( b > maxval ) b = maxval;
  289.             PPM_ASSIGN( *nxP, r, g, b );
  290.             rs[col] = gs[col] = bs[col] = HALFSCALE;
  291.             }
  292.         break;
  293.  
  294.         default:
  295.         for ( col = 0, xP = xelrow, nxP = tempxelrow;
  296.               col < cols; ++col, ++xP, ++nxP )
  297.             {
  298.             register long g;
  299.  
  300.             g = gs[col] + fracrowtofill * PNM_GET1( *xP );
  301.             g /= SCALE;
  302.             if ( g > maxval ) g = maxval;
  303.             PNM_ASSIGN1( *nxP, g );
  304.             gs[col] = HALFSCALE;
  305.             }
  306.         break;
  307.         }
  308.         fracrowleft -= fracrowtofill;
  309.         if ( fracrowleft == 0 )
  310.         {
  311.         fracrowleft = syscale;
  312.         needtoreadrow = 1;
  313.         }
  314.         fracrowtofill = SCALE;
  315.         }
  316.  
  317.     /* Now scale X from tempxelrow into newxelrow and write it out. */
  318.     if ( newcols == cols )    /* shortcut X scaling if possible */
  319.         pnm_writepnmrow( stdout, tempxelrow, newcols, maxval, newformat, 0 );
  320.     else
  321.         {
  322.         register long r, g, b;
  323.         register long fraccoltofill, fraccolleft;
  324.         register int needcol;
  325.  
  326.         nxP = newxelrow;
  327.         fraccoltofill = SCALE;
  328.         r = g = b = HALFSCALE;
  329.         needcol = 0;
  330.         for ( col = 0, xP = tempxelrow; col < cols; ++col, ++xP )
  331.         {
  332.         fraccolleft = sxscale;
  333.         while ( fraccolleft >= fraccoltofill )
  334.             {
  335.             if ( needcol )
  336.             {
  337.             ++nxP;
  338.             r = g = b = HALFSCALE;
  339.             }
  340.             switch ( PNM_FORMAT_TYPE(format) )
  341.             {
  342.             case PPM_TYPE:
  343.             r += fraccoltofill * PPM_GETR( *xP );
  344.             g += fraccoltofill * PPM_GETG( *xP );
  345.             b += fraccoltofill * PPM_GETB( *xP );
  346.             r /= SCALE;
  347.             if ( r > maxval ) r = maxval;
  348.             g /= SCALE;
  349.             if ( g > maxval ) g = maxval;
  350.             b /= SCALE;
  351.             if ( b > maxval ) b = maxval;
  352.             PPM_ASSIGN( *nxP, r, g, b );
  353.             break;
  354.  
  355.             default:
  356.             g += fraccoltofill * PNM_GET1( *xP );
  357.             g /= SCALE;
  358.             if ( g > maxval ) g = maxval;
  359.             PNM_ASSIGN1( *nxP, g );
  360.             break;
  361.             }
  362.             fraccolleft -= fraccoltofill;
  363.             fraccoltofill = SCALE;
  364.             needcol = 1;
  365.             }
  366.         if ( fraccolleft > 0 )
  367.             {
  368.             if ( needcol )
  369.             {
  370.             ++nxP;
  371.             r = g = b = HALFSCALE;
  372.             needcol = 0;
  373.             }
  374.             switch ( PNM_FORMAT_TYPE(format) )
  375.             {
  376.             case PPM_TYPE:
  377.             r += fraccolleft * PPM_GETR( *xP );
  378.             g += fraccolleft * PPM_GETG( *xP );
  379.             b += fraccolleft * PPM_GETB( *xP );
  380.             break;
  381.  
  382.             default:
  383.             g += fraccolleft * PNM_GET1( *xP );
  384.             break;
  385.             }
  386.             fraccoltofill -= fraccolleft;
  387.             }
  388.         }
  389.         if ( fraccoltofill > 0 )
  390.         {
  391.         --xP;
  392.         switch ( PNM_FORMAT_TYPE(format) )
  393.             {
  394.             case PPM_TYPE:
  395.             r += fraccoltofill * PPM_GETR( *xP );
  396.             g += fraccoltofill * PPM_GETG( *xP );
  397.             b += fraccoltofill * PPM_GETB( *xP );
  398.             break;
  399.  
  400.             default:
  401.             g += fraccoltofill * PNM_GET1( *xP );
  402.             break;
  403.             }
  404.         }
  405.         if ( ! needcol )
  406.         {
  407.                 switch ( PNM_FORMAT_TYPE(format) )
  408.                     {
  409.                     case PPM_TYPE:
  410.             r /= SCALE;
  411.             if ( r > maxval ) r = maxval;
  412.             g /= SCALE;
  413.             if ( g > maxval ) g = maxval;
  414.             b /= SCALE;
  415.             if ( b > maxval ) b = maxval;
  416.             PPM_ASSIGN( *nxP, r, g, b );
  417.                     break;
  418.  
  419.                     default:
  420.             g /= SCALE;
  421.             if ( g > maxval ) g = maxval;
  422.             PNM_ASSIGN1( *nxP, g );
  423.                     break;
  424.                     }
  425.         }
  426.         pnm_writepnmrow( stdout, newxelrow, newcols, maxval, newformat, 0 );
  427.         }
  428.     }
  429.  
  430.     pm_close( ifp );
  431.     pm_close( stdout );
  432.  
  433.     exit( 0 );
  434.     }
  435.